#include <sys/select.h>
#include <poll.h>
#include "sock.hpp"

#define NFDSET_NUM 1024
#define DEL -1
#define BUFFER_SIZE 1024
#define CLIENT_CLOSE 0
#define RECV_ERROR 1

// pollfd数组
vector<pollfd> fdArray;
unordered_map<int, string> UserNetworkData;

void Format(const char *str);
void PrintfdArray();
void EstablishMap(int, string &, uint16_t &);
void recvError_Or_Close(int flags, struct pollfd& fds, string &UserData);
void HandlerEvent(int listensockfd);

//=========================================================================================

int main(int argc, char *argv[])
{
    if (argc < 2)
        Format(argv[0]);
    std::string ip;
    if (argc == 3)
        ip = argv[1];

    int listensockfd = Sock::Socket();
    if (listensockfd < 0)
        exit(4);
    Sock::Bind(listensockfd, ip, std::stoi(argv[2]));
    Sock::Listen(listensockfd);

    struct pollfd PollFd;
    PollFd.fd = DEL;
    PollFd.events = 0;
    PollFd.revents = 0;
    fdArray.resize(NFDSET_NUM, PollFd);   // 初始化数组 -- 一共可以保存NFDSET_NUM个fd
    fdArray[0].fd = listensockfd;         // 0下标默认为sockfd
    fdArray[0].events = POLLIN;           // 设置监听事件为可读事件
    int timeout = -1;                     // 单位：毫秒 -- -1为永久阻塞

    while (true)
    {
        // 编写多路转接代码, 必须等待事件就绪了, 才能调用IO函数
        int n = poll(&fdArray[0], NFDSET_NUM, timeout);

        switch (n)
        {
        case 0:
            cout << "time out....... --> (时间戳: " << (unsigned long)time(nullptr) << ")" << endl;
            break;
        case -1:
            cerr << "select error: " << strerror(errno) << endl;
            exit(4);
            break;
        default:
            // 等待成功
            HandlerEvent(listensockfd);
            break;
        }
    }
    return 0;
}

//=========================================================================================

void Format(const char *str)
{
    std::cout << "Format: " << str << "  [ip]  port" << std::endl;
    exit(3);
}

void PrintfdArray()
{
    cout << "当前合法sock fd: ";
    for (auto fd : fdArray)
    {
        if (fd.fd != DEL)
            cout << fd.fd << " ";
    }
    cout << endl;
}

//=========================================================================================

// 建立serverfd和Client网络基本数据的映射关系
void EstablishMap(int serverfd, string &ClientIp, uint16_t &ClientPort)
{
    string UserData = ClientIp + ":" + std::to_string(ClientPort);
    UserNetworkData[serverfd] = UserData;
}

//=========================================================================================

// 通过标记位判断recv读取时出现什么错误
void recvError_Or_Close(int flags, struct pollfd& fds, string &UserData)
{
    if (flags == CLIENT_CLOSE)
        cout << "Client[" << UserData << "] quit, server close, fd: " << fds.fd << endl;
    else if (flags == RECV_ERROR)
        cout << "Client[" << UserData << "] quit, Server recv error, fd: " << fds.fd << endl;

    close(fds.fd);
    fds.fd = DEL;       // 去除对该文件描述符在poll中fd（-1不是有效的fd）
    fds.events = 0;     // 重置监听事件位图
    fds.revents = 0;    // 重置就绪事件位图

    PrintfdArray(); // Debug
}

void HandlerEvent(int listensockfd)
{
    auto It = fdArray.begin();
    for (; It != fdArray.end(); ++It)
    {
        if ((*It).fd == DEL)
            continue;
            
        // 按连接事件就绪类进行处理 -- 获取服务连接fd（IO类fd）并且放到poll进行事件就绪监听
        if (It == fdArray.begin() && (*It).fd == listensockfd)
        {
            // 判断listensockfd在poll的revents“读事件是否就绪”（是否有连接已经完成三次握手被放到全连接队列，等待拿(accept)上去）
            if ((*It).revents & POLLIN)
            {
                cout << "等待成功!!! --> (时间戳: " << (unsigned long)time(nullptr) << ")" << endl;
                string ClientIp;
                uint16_t ClientPort;

                int serverfd = Sock::Accept(listensockfd, &ClientIp, &ClientPort); // 不会阻塞，连接事件已经就绪
                EstablishMap(serverfd, ClientIp, ClientPort);                      // 建立ip和port映射关系，保存用户网络数据

                // read/write不知道底层的缓冲区是否有数据读取和缓冲区是否满了不能写入数据（“等”的过程）
                // 这里也要把serverfd交给select进行事件就绪监听 -- 这里是监听“IO事件” -- 前面监听的是“连接事件”
                auto It2 = fdArray.begin();
                while (It2 != fdArray.end())
                {
                    if ((*It2).fd == DEL)
                        break;
                    ++It2;
                }
                if (It2 == fdArray.end())
                {
                    cerr << "Server已经到最大的上限, 无法保持更多的连接了!!!" << endl;
                    close(serverfd);
                }
                else
                {
                    int Index = It2 - fdArray.begin();
                    fdArray[Index].fd = serverfd;    // 完成将serverfd放到数组中
                    fdArray[Index].events = POLLIN;  // 并且设置读事件监听

                    PrintfdArray();   // Debug
                }
            }
        }
        else
        {
            // 处理IO类事件就绪 -- read/recv...
            if ((*It).revents & POLLIN)
            {
                char buffer[BUFFER_SIZE];
                string UserData;
                ssize_t rcv = recv((*It).fd, buffer, BUFFER_SIZE - 1, 0);
                if (rcv > 0)
                {
                    buffer[rcv] = '\0';
                    for (auto KV : UserNetworkData)
                    {
                        if (KV.first == (*It).fd)
                        {
                            UserData = KV.second;
                            cout << "Client[" << UserData << "]" << "# " << buffer << endl;
                            break;
                        }
                    }
                }
                else if (recv == 0)
                {
                    recvError_Or_Close(CLIENT_CLOSE, *It, UserData);
                }
                else
                {
                    recvError_Or_Close(RECV_ERROR, *It, UserData);
                }
            }
        }
    }
}
